﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Lacrima.Framework.Infrastructure
{
    public static class Generator
    {
        /// <summary>
        /// 随机数生成工具
        /// </summary>
        public static readonly Random Rand = new Random();

        /// <summary>
        /// 全局唯一值生成工具
        /// </summary>
        /// <value>全局唯一值</value>
        public static string UID
        {
            get
            {
                return Guid.NewGuid().ToString();
            }
        }

        /// <summary>
        /// 通过随机数生成随机布尔值
        /// </summary>
        /// <value>随机的布尔值</value>
        public static bool RandomBoolean
        {
            get
            {
                return (int)Math.Ceiling(Math.Sin(Rand.Next())) == 1;
            }
        }

        /// <summary>
        /// 默认日期
        /// </summary>
        public static DateTime DefaultDate = DateTime.Parse("1900/01/01");


        /// <summary>
        /// 获取随机日期时间
        /// </summary>
        /// <returns>返回随机日期时间</returns>
        public static DateTime RandomDateTime
        {
            get
            {
                int randOffset = Rand.Next(32);
                DateTime randDateTime = new DateTime((long)Rand.Next() << randOffset);
                return randDateTime;
            }
        }

        /// <summary>
        /// 创建数组对象方法
        /// </summary>
        /// <typeparam name="TResult">数组类</typeparam>
        /// <param name="length">数组长度</param>
        /// <returns>返回生成的数组对象</returns>
        public static TResult[] CreateArray<TResult>(int length = 1, TResult defaultValue = default(TResult))
            where TResult : new()
        {
            if (typeof(TResult).IsAbstract)
                return null;
            else
            {
                TResult[] array = new TResult[length];
                for (int index = 0; index < length; ++index)
                {
                    array[index] = defaultValue == null ? Activator.CreateInstance<TResult>() : defaultValue;
                }
                return array;
            }
        }

        /// <summary>
        /// 获取枚举类型的随机值
        /// </summary>
        /// <param name="propertyType">枚举类型</param>
        /// <returns>该枚举类型的随机枚举值</returns>
        public static object GetRandomEnumValue(Type propertyType)
        {
            // 设置随机枚举值
            if (propertyType.IsEnum)
            {
                Array enumValues = propertyType.GetEnumValues();
                IEnumerator enumerator = enumValues.GetEnumerator();
                int randIndex = Rand.Next(0, enumValues.Length);
                for (int index = 0; index < enumValues.Length && enumerator.MoveNext(); ++index)
                {
                    if (index == randIndex)
                    {
                        return enumerator.Current;
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// 获取枚举类型的随机值
        /// </summary>
        /// <param name="propertyType">枚举类型</param>
        /// <returns>该枚举类型的随机枚举值</returns>
        public static TEnum GetRandomEnumValue<TEnum>()
        {
            TEnum result = default(TEnum);
            var propertyType = typeof(TEnum);
            // 设置随机枚举值
            if (propertyType.IsEnum)
            {
                Array enumValues = propertyType.GetEnumValues();
                IEnumerator enumerator = enumValues.GetEnumerator();
                int randIndex = Rand.Next(0, enumValues.Length);
                for (int index = 0; index < enumValues.Length && enumerator.MoveNext(); ++index)
                {
                    if (index == randIndex)
                    {
                        result = (TEnum)enumerator.Current;
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// 生成实体类对象
        /// </summary>
        /// <typeparam name="TEntity">实体类类型</typeparam>
        /// <returns>返回生成的实体类对象</returns>
        public static TEntity CreateEntity<TEntity>()
            where TEntity : class,new()
        {
            TEntity entity = new TEntity();
            PropertyInfo[] properties = typeof(TEntity).GetProperties()
                                                       .Where(o => o.PropertyType.IsValueType || o.PropertyType.IsEquivalentTo(typeof(string)))
                                                       .ToArray();
            foreach (PropertyInfo property in properties)
            {
                Type propertyType = property.PropertyType;
                if (propertyType.IsEquivalentTo(typeof(DateTime)))
                {
                    // 设置当前时间
                    property.SetValue(entity, DateTime.Now);
                }
                else if (propertyType.IsEquivalentTo(typeof(string)))
                {
                    // 设置全局唯一值
                    property.SetValue(entity, UID);
                }
                else if (propertyType.IsEnum)
                {
                    // 设置随机枚举值
                    property.SetValue(entity, GetRandomEnumValue(propertyType));
                }
                else if (typeof(bool).IsEquivalentTo(propertyType))
                {
                    // 设置随机布尔值
                    property.SetValue(entity, RandomBoolean);
                }
                else
                {
                    // 设置随机数值
                    property.SetValue(entity, Convert.ChangeType(Rand.Next(), propertyType));
                }
            }
            return entity;
        }

//        /// <summary>
//        /// 判断两个对象的各个属性值是否相等
//        /// 该方法遵循系统自身判断规则，即null值比较时返回false，并且在成员变量为类对象时调用类自身的Equals方法
//        /// (这里存在一个问题：如果类中的成员变量存在null值则直接返回false)
//        /// </summary>
//        /// <typeparam name="T">比较的对象类型</typeparam>
//        /// <param name="source">源对象</param>
//        /// <param name="target">目标对象</param>
//        /// <returns> 如果对象的各个属性值相等则返回true，否则返回false</returns>
//        public static bool EqualsTo<T>(this T source, T target, bool isStrictRule = false, bool ignoreNull = true) where T : class
//        {
//#if DEBUG
//            string debugPropertyName = "debugProperty";
//#endif

//            if (source == target)
//                return true;

//            Type sourceType = source.GetType();
//            // 注意这里两个对象为空值时也是相等的，否则在下面的递归调用中遇到字段为空时将返回false
//            if (source == null || target == null)
//            {
//                if (isStrictRule)
//                    return false;
//                else
//                    return (source == null && target == null);
//            }
//            else if (sourceType.IsPrimitive || sourceType.IsEnum || sourceType.IsValueType || typeof(string).IsAssignableFrom(sourceType))
//            {
//                // 这里的sourceType.IsPrimitive || sourceType.IsEnum可以省略，因为只用sourceType.IsValueType就够了
//                return source.Equals(target);
//            }
//            else
//            {
//                bool flag = true;
//                PropertyInfo[] properties = source.GetType().GetProperties();

//                foreach (var property in properties)
//                {

//#if DEBUG  // 用于调试特殊字段时使用
//                    if (property.Name.Equals(debugPropertyName))
//                    {
//                        Debug.WriteLine(debugPropertyName);
//                    }
//#endif
//                    // 判断非集合类属性值是否相等，注意string类也继承了IEnumerable接口
//                    if (!typeof(IEnumerable).IsAssignableFrom(property.PropertyType) || typeof(string).IsAssignableFrom(property.PropertyType))
//                    {
//                        if (property.GetValue(source) == null)
//                        {
//                            // 如果类中的成员变量存在null即返回false放开以下代码
//                            if (isStrictRule) return false;
//                            // 如果类中的成员变量不存在null
//                            else if (ignoreNull) flag &= true;
//                            else flag &= (property.GetValue(target) == null);
//                        }
//                        else
//                        {
//                            flag &= property.GetValue(source).EqualsTo(property.GetValue(target), isStrictRule, ignoreNull);
//                        }

//                        if (flag == false)
//                        {
//#if DEBUG
//                            Debug.WriteLine(string.Format("The value of source property \"{0}\" not equals to the target!", property.Name));
//                            Debug.WriteLine(string.Format("Compared property name is： {0}", property.Name));
//                            Debug.WriteLine(string.Format("Compared property type is： {0}", property.PropertyType.Name));
//                            Debug.WriteLine(string.Format("The source property value is： {0}", property.GetValue(source) == null ? "null" : property.GetValue(source)));
//                            Debug.WriteLine(string.Format("The target property value is： {0}", property.GetValue(target) == null ? "null" : property.GetValue(target)));
//#endif
//                            return flag;
//                        }
//                    }
//                }
//                // 判断非集合类属性值是否相等
//                return flag;
//            }
//        }

        /// <summary>
        /// 将枚举结合拼接为字符串
        /// </summary>
        public static string JoinToString<T>(this IEnumerable<T> source, string separator = ",")
        {
            return string.Join(separator, source.ToArray()); ;
        }
    }
}
